【buu】【另一种抽象的xxtea】[2019红帽杯]xx

b题看了一整天,总算是看明白了TMD


查克无壳64位,拖入ida

发现一很大一坨代码,慢慢分析吧

put_in

有个输入函数和v6

这里的v6后面的Code不是上面要输入Code,跟进发现是另外的一串字符


check

这里也是要吐槽煞笔ida伪代码的反编译的表达形式

*(v9 + Code - v5)表示的code[v9-v5]

这v13是检测v6的长度

if语句是遍历检测输入的字符是否在v6的范围内,是的话就跳出循环,

如果有不属于v6的字符存在v11就会累加到36

v14这一小段也是检测v6长度

当有不属于v6的字符存在时就会退出

v9 - v5 < 4表达的是这一段代码只截取输入的前四个字符


check2

这里v3搞错了应该是19,这里的code是输入

v30动调出来的是输入的flag的前四个字符

下面的连续的4个 if 表明前四个字符不能是0


key_exbend&xxtea&mix

首先这个循环是一个密钥扩展,是把输入的flag前四个字母扩展成16位,也就是4个4位的密钥

然后内个sub_7FF7ADD11AB0是比较抽象的xxtea加密,具体是用一个插件FindCrypt和结合题目猜测可能是xxtea

Size是动调出来的是个固定值24

然后就是进行位置交换混淆


xor&enc

这里的异或最开始没看懂

首先是这个++v22这个v22可以认为是一个数组,++v22是指向数组的后一个元素

然后里面的if语句表示要从3开始异或,所以前三个(0-2)元素不会进行操作

当从3开始会进行异或,把当前的v22的值从0位置开始的v20进行异或

每三个元素为一组,每组比上一组多进行一次异或,

多进行的那一次异或,是将刚才异或得到的值与**v20[(刚才得值+1)]**进行异或

一直到v21 = 23进行最后一次循环

v30 v30[1] v31 v32是密文。但是要注意小端序,建议动调调到这里直接提取


综上我们先把换位混淆的密文和迭代异或先给解回去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
int mix[] = { 0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B,
0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8,
0xE7, 0x56, 0x56, 0xFA};

int enc[24];
int count = 0;

for (int i = 23; i >=3; i--)
{

for (int j = 6-count; j >= 0; j--)
{
mix[i]^=mix[j];
}
if (i % 3 == 0)
{
count++;
}

}
enc[2] = mix[0];
enc[0] = mix[1];
enc[3] = mix[2];
enc[1] = mix[3];
enc[6] = mix[4];
enc[4] = mix[5];
enc[7] = mix[6];
enc[5] = mix[7];
enc[10] = mix[8];
enc[8] = mix[9];
enc[11] = mix[10];
enc[9] = mix[11];
enc[14] = mix[12];
enc[12] = mix[13];
enc[15] = mix[14];
enc[13] = mix[15];
enc[18] = mix[16];
enc[16] = mix[17];
enc[19] = mix[18];
enc[17] = mix[19];
enc[22] = mix[20];
enc[20] = mix[21];
enc[23] = mix[22];
enc[21] = mix[23];

for (int i = 0; i < 24; i++)
printf("0x%x,", enc[i]);

return 0;
}

然后再找一个xxtea脚本进行解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
}while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}while (--rounds);
}
}


int main()
{
uint32_t v[6]= {0x40cea5bc,0xe7b2b2f4,0x129d12a9,0x5bc810ae,0x1d06d73d,0xdcf870dc};
uint32_t const k[4]= {(unsigned int)0x67616c66,(unsigned int)0x0,(unsigned int)0x0,(unsigned int)0x0};
int n = 6;
btea(v, -n, k);
// printf("解密后的数据:%x %x %x %x %x %x\n", v[0], v[1],v[2],v[3],v[4],v[5]);
for(int i = 0; i<6 ; i++)
printf("%x\n",v[i]);
return 0;
}

然后把的出来的16进制转换成字符,注意小端序